package com.s54.common.service;

import cn.hutool.http.useragent.UserAgentUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.s54.common.constants.CacheConstants;
import com.s54.common.beans.AuthUser;
import com.s54.common.beans.Token;
import com.s54.common.context.ThreadContextHolder;
import com.s54.common.enums.CachePrefix;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.UUID;

import static com.s54.common.constants.CacheConstants.DELIMITER;

@Service
@RequiredArgsConstructor
public class TokenService {
    private final RedisService redisService;

    /**
     * 生成accessToken，并缓存到redis.
     * key:    S54:PC_TOKEN/MOBILE_TOKEN:{username(md5)}:{uuid}
     * value: json格式的authUser信息
     * @param authUser
     * @return accessToken: {username(md5)}:{uuid}
     */
    @SneakyThrows
    public Token createToken(AuthUser authUser) {
        String user = new ObjectMapper().writeValueAsString(authUser);
        String usernameHash = DigestUtils.md5DigestAsHex(authUser.getUsername().getBytes(StandardCharsets.UTF_8));
        String accessToken = usernameHash + DELIMITER + UUID.randomUUID().toString().replace("-", "");
        // 强制下线用户
        String userAgent = getCurrentUserAgent();
        forceLogout(usernameHash, userAgent);
        // 缓存登录用户
        String key = getTokenKey(accessToken, userAgent);
        if (isMobile(userAgent)) {
            redisService.set(key, user);
        } else {
            redisService.set(key, user, Duration.ofMinutes(CacheConstants.EXPIRE_TIME));
        }
        return new Token(accessToken);
    }

    public Boolean removeToken(String accessToken) {
        return redisService.del(getTokenKey(accessToken, getCurrentUserAgent()));
    }
    @SneakyThrows
    public AuthUser getUser(String accessToken, String userAgent) {
        String user = redisService.get(getTokenKey(accessToken, userAgent));
        if (user == null) return null;
        return new ObjectMapper().readValue(user, AuthUser.class);
    }
    public boolean isValid(String accessToken, String userAgent) {
        return redisService.hasKey(getTokenKey(accessToken, userAgent));
    }

    private String getCurrentUserAgent() {
        return ThreadContextHolder.getHttpRequest().getHeader(HttpHeaders.USER_AGENT);
    }
    private String getTokenKey(String accessToken, String userAgent) {
        String prefix = isMobile(userAgent) ? CachePrefix.MOBILE_TOKEN.getPrefix() : CachePrefix.PC_TOKEN.getPrefix();
        return String.join(DELIMITER, prefix, accessToken);
    }

    private void forceLogout(String usernameHash, String userAgent) {
        String prefix = isMobile(userAgent) ? CachePrefix.MOBILE_TOKEN.getPrefix() : CachePrefix.PC_TOKEN.getPrefix();
        redisService.del(redisService.keys(String.join(DELIMITER, prefix, usernameHash, "*")));
    }

    private boolean isMobile(String userAgent) {
        return UserAgentUtil.parse(userAgent).isMobile();
    }
}
